package com.zkh.myutils.database.conutils;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.function.Consumer;

import com.zkh.myutils.database.DatabaseException;
import com.zkh.myutils.database.dbpool.ConnectConfigure;
import com.zkh.myutils.database.dbpool.DataSourceAdapter;
import com.zkh.myutils.database.dbpool.DbPoolDataSource;
import com.zkh.myutils.io.IOUtils;

/**
 * 数据库连接池工具类，只使用默认数据源。
 * @author zkh
 *
 */
public class PoolUtils {
	// 事务连接，使用事务时，内部自动调用
	private static ThreadLocal<Connection> threadlocal = new ThreadLocal<Connection>();
	
	/**
	 * 获取默认数据源 
	 * @return 数据源
	 */
	public static DbPoolDataSource getDataSource() {
		return DataSourceAdapter.getInstanceOfDataSource();
	}
	
	/**
	 * 获取指定数据源 
	 * @return 数据源
	 */
	public static DbPoolDataSource getDataSource(String datasourceKey){
		//获取数据源
		return DataSourceAdapter.getInstanceOfDataSource(datasourceKey);
	}
	
	/**
	 * 获取默认数据源的连接，使用后必须手动调用close方法释放资源。
	 * @return
	 */
	public static Connection getConnection() {
		return getConnection(ConnectConfigure.getDefualtSource());
	}
	
	/**
	 * 获取指定数据源的连接，使用后必须手动调用close方法释放资源。
	 * @return
	 */
	public static Connection getConnection(String datasourceKey){
		try {
			return getDataSource(datasourceKey).getConnection();
		} catch (SQLException e) {
			throw new DatabaseException(e);
		}
	}
	
	/**
	 * 获取事务连接。如果未开启事务，则返回null<br />
	 * <b>事务连接在提交或回滚事务时，会自动关闭连接，故不用手动关闭。</b>
	 * @return 事务连接
	 */
	public static Connection getTransactionConnection(){
		//获取事务连接
		return threadlocal.get();
	}
	
	/**
	 * 开始一个新事务
	 * @param connection 指定事务连接。如果该连接为null，则获取一个新连接作为事务连接
	 * @return 事务连接。当connection不为null时，即返回该对象
	 */
	public static Connection beginNewTransaction(Connection connection) {
		return beginNewTransaction(connection, ConnectConfigure.getDefualtSource());
	}
	
	/**
	 * 开始一个新事务
	 * @param connection 指定事务连接。如果该连接为null，则获取一个新连接作为事务连接
	 * @param datasourceKey 指定数据源key
	 * @return 事务连接。当connection不为null时，即返回该对象
	 */
	public static Connection beginNewTransaction(Connection connection, String datasourceKey) {
		//连接不存在，则获取一个连接作为事务连接
		if(connection==null) {
			//获取连接
			connection = getConnection(datasourceKey);
			//关闭自动提交
			try {
				connection.setAutoCommit(false);
			} catch (SQLException e) {
				throw new DatabaseException(e);
			}
		}
		//设置事务连接
		threadlocal.set(connection);
		//返回事务连接
		return connection;
	}
	
	/**
	 * 关闭连接
	 * @param conn
	 */
	public static void close(Connection conn){
		//如果连接不为空，则关闭连接
		IOUtils.closeQuietly(conn, e->new DatabaseException(e));
	}
	
	/**
	 * 开启默认数据源事务
	 */
	public static void beginTransaction() {
		beginTransaction(ConnectConfigure.getDefualtSource());
	}
	
	/**
	 * 开启指定数据源事务
	 */
	public static void beginTransaction(String datasourceKey){
		//获取事务连接
		Connection transactionConnection = threadlocal.get();
		//检测事务连接
		if(transactionConnection==null){
			transactionConnection = getConnection(datasourceKey);
		}else{
			throw new DatabaseException("系统已开启事务，请提交上次事务后再开启新事务");
		}
		//关闭自动提交
		try {
			transactionConnection.setAutoCommit(false);
			//保存事务连接
			threadlocal.set(transactionConnection);
		} catch (SQLException e) {
			throw new DatabaseException(e);
		}
	}
	
	/**
	 * 提交事务
	 */
	public static void commit(){
		//获取事务连接
		Connection transactionConnection = threadlocal.get();
		//检测事务连接
		if(transactionConnection==null){
			throw new DatabaseException("未开启事务，提交失败");
		}else{
			//还原事务连接
			restoreTransactionConnection(transactionConnection, conn->{
				try {
					//提交事务
					conn.commit();
					//删除事务连接
					threadlocal.remove();
				} catch (SQLException e) {
					throw new DatabaseException(e);
				}
			});
		}
	}
	
	/**
	 * 回滚事务
	 */
	public static void rollback(){
		//获取事务连接
		Connection transactionConnection = threadlocal.get();
		//检测事务连接
		if(transactionConnection==null){
			throw new DatabaseException("未开启事务，回滚失败");
		}else{
			//还原事务连接
			restoreTransactionConnection(transactionConnection, conn->{
				try {
					//回滚事务
					conn.rollback();
					//删除事务连接
					threadlocal.remove();
				} catch (SQLException e) {
					throw new DatabaseException(e);
				}
			});
		}
	}
	
	/**
	 * 还原事务连接
	 * @param connection 事务连接
	 * @param consumer 自定义操作
	 */
	public static void restoreTransactionConnection(Connection connection, Consumer<Connection> consumer) {
		try {
			//自定义操作
			consumer.accept(connection);
			//开启自动提交
			connection.setAutoCommit(true);
			//释放连接
			close(connection);
		} catch (SQLException e) {
			throw new DatabaseException(e);
		}
	}
}